﻿/*
 * Copyright (C) 2023 - 2024 lchfj.cn
 * 
 * This file is part of FastestHost.
 * 
 * FastestHost is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * FastestHost is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with FastestHost. If not, see <https://www.gnu.org/licenses/>.
 */

using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Cn.Lchfj.FastestHost.Network;

namespace Cn.Lchfj.FastestHost
{
    [JsonSerializable(typeof(RunSetting))]
    [JsonSourceGenerationOptions(JsonSerializerDefaults.Web)]
    internal partial class RunSettingJsonContext : JsonSerializerContext
    {

    }

    internal record RunSetting()
    {
        internal enum CommandTypeEnums
        {
            Unknow = -1,

            Install = 1,
            UnInstall = 2,
            RunOneTime = 3,
            Update = 4,

            AutoRun = 101,
            UpdateFile = 102,
        }

        internal enum RunTypeEnums
        {
            Network = 1,
            Local = 2
        }


        public required CommandTypeEnums Command { get; init; }
        public required RunTypeEnums RunType { get; init; }

        public required IReadOnlyList<string> Path { get; init; }

        internal static RunSetting? ReadFromArgs(string[] args)
        {
            if (args is not { Length: > 0 })
                return null;

            var text = args.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a));
            if (string.IsNullOrWhiteSpace(text))
                return null;

            var bytes = Convert.FromHexString(text.Trim());
            var json = Encoding.UTF8.GetString(bytes);

            return JsonSerializer.Deserialize(json, RunSettingJsonContext.Default.RunSetting);
        }

        internal string GetArgument()
        {
            var bytes = JsonSerializer.SerializeToUtf8Bytes(this, RunSettingJsonContext.Default.RunSetting);
            return Convert.ToHexString(bytes);
        }


        internal static RunSetting? CreatNew()
        {
            ConsoleHelper.ShowWindow();

            var setting = new RunSetting() { Command = CommandTypeEnums.Unknow, Path = [], RunType = RunTypeEnums.Network };

            ConsoleHelper.WriteLine("欢迎使用  FastestHost");
            ConsoleHelper.WriteLine("CopyRight @ 2023 - 2024 lchfj.cn ");
            ConsoleHelper.WriteLine();


            ConsoleHelper.WriteLine("请选择您的目的");
            ConsoleHelper.WriteLine("1：安装自启动应用（请先将本应用放置到您希望的位置）");
            ConsoleHelper.WriteLine("2：关闭自启动");
            ConsoleHelper.WriteLine("3：单次运行");
            ConsoleHelper.WriteLine("4：更新应用");
            setting = setting with { Command = (CommandTypeEnums)ReadNumber(1, 4) };
            if (setting.Command is CommandTypeEnums.Update or CommandTypeEnums.UnInstall)
                return setting;


            ConsoleHelper.WriteLine("请选择运行方式");
            ConsoleHelper.WriteLine("1：联网运行（仅支持特定方案运行，除DNS解析外也从服务器获取其他用户共享的解析记录，相对应也会将本机的DNS解析记录发送到服务器共享给他人使用）");
            ConsoleHelper.WriteLine("2：单机运行（仅使用DNS解析获取IP地址，但可以自定义域名进行检查）");
            setting = setting with { RunType = (RunTypeEnums)ReadNumber(1, 2) };




            return setting.RunType switch
            {
                RunTypeEnums.Network => CreateNetworkSetting(setting),
                RunTypeEnums.Local => CreateLocalSetting(setting),
                _ => null,
            };
        }

        private static RunSetting CreateLocalSetting(RunSetting setting)
        {
            var list = new List<string>();
            while (true)
            {
                ConsoleHelper.WriteLine("请输入要使用的本地文件地址或网络地址（http 或 https）");
                ConsoleHelper.WriteLine("一行一个文件地址，允许多个，空行结束输入");
                ConsoleHelper.WriteLine("文件要求为文本文档，每行一个主机名");
                while (true)
                {
                    var path = ConsoleHelper.ReadLine();
                    if (string.IsNullOrWhiteSpace(path))
                        break;

                    if (path.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || path.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                    {
                        list.Add(path);
                    }
                    else if (File.Exists(path))
                    {
                        list.Add(path);
                    }
                    else
                    {
                        ConsoleHelper.WriteLine("输入的文件不存在！");
                    }
                }




                if (list.Count > 0)
                {
                    ConsoleHelper.WriteLine();
                    return setting with { Path = list };
                }
            }
        }

        private static RunSetting? CreateNetworkSetting(RunSetting setting)
        {
            ConsoleHelper.WriteLine();
            var schemeList = RunHelper.Run(ApiClient.Instance.GetSchemeListAsync);
            if (schemeList is not { Count: > 0 })
            {
                ConsoleHelper.SetForegroundColor(ConsoleColor.Red);
                ConsoleHelper.WriteLine("获取方案列表失败，请关闭后重试！");
                ConsoleHelper.ReadLine();
                return null;
            }


            ConsoleHelper.WriteLine("请选择要使用的方案（多个以空格分隔）：");
            ConsoleHelper.WriteLine("0：以下全部");
            for (var i = 0; i < schemeList.Count; i++)
            {
                ConsoleHelper.Write(i + 1);
                ConsoleHelper.Write('：');
                ConsoleHelper.Write(schemeList[i].Name);
                ConsoleHelper.WriteLine();
            }

            var selected = ReadNumberList(0, schemeList.Count);
            if (selected.Contains(0))
                setting = setting with { Path = [] };
            else
                setting = setting with { Path = selected.Select(s => schemeList[s - 1].Id).ToArray() };

            return setting;
        }

        private static int ReadNumber(int min, int max)
        {
            return ReadNumberList(min, max).First();
        }


        private static List<int> ReadNumberList(int min, int max)
        {
            while (true)
            {
                var success = true;
                var list = new List<int>();
                var text = ConsoleHelper.ReadLine() ?? string.Empty;
                foreach (var item in text.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
                {
                    if (int.TryParse(item, out var value))
                    {
                        if (value >= min && value <= max)
                        {
                            list.Add(value);
                            continue;
                        }
                    }

                    success = false;
                    break;
                }

                ConsoleHelper.WriteLine();
                if (list.Count > 0 && success)
                {
                    return list;
                }

                ConsoleHelper.WriteLine("请重新输入：");
            }
        }
    }
}
